home *** CD-ROM | disk | FTP | other *** search
/ 3D Images / 3D Images.iso / programs / amiga / rayshade / libshade / picture.c < prev    next >
C/C++ Source or Header  |  1995-01-12  |  8KB  |  355 lines

  1. /*
  2.  * picture.c
  3.  *
  4.  * Copyright (C) 1989, 1991, Craig E. Kolb, Rod G. Bogart
  5.  * All rights reserved.
  6.  *
  7.  * This software may be freely copied, modified, and redistributed
  8.  * provided that this copyright notice is preserved on all copies.
  9.  *
  10.  * You may not distribute this software, in whole or in part, as part of
  11.  * any commercial product without the express consent of the authors.
  12.  *
  13.  * There is no warranty or other guarantee of fitness of this software
  14.  * for any purpose.  It is provided solely "as is".
  15.  *
  16.  * picture.c,v 4.1 1994/08/09 08:04:43 explorer Exp
  17.  *
  18.  * picture.c,v
  19.  * Revision 4.1  1994/08/09  08:04:43  explorer
  20.  * Bump version to 4.1
  21.  *
  22.  * Revision 1.1.1.1  1994/08/08  04:52:17  explorer
  23.  * Initial import.  This is a prerelease of 4.0.6enh3, or 4.1 possibly.
  24.  *
  25.  * Revision 4.0.1.2  92/02/07  09:22:20  cek
  26.  * patch6: Fixed typo in MTV error message.
  27.  * 
  28.  * Revision 4.0.1.1  92/01/10  16:28:28  cek
  29.  * patch3: Added check for nonexistent patial image file.
  30.  * patch3: Fixed declaration of nrow in count_rle_rows().
  31.  * patch3: Changed level of several error messages.
  32.  * 
  33.  * Revision 4.0  91/07/17  14:47:00  kolb
  34.  * Initial version.
  35.  * 
  36.  */
  37. #include "rayshade.h"
  38. #include "picture.h"
  39. #include "viewing.h"
  40. #include "options.h"
  41. #include "stats.h"
  42. #include "zbuf.h"
  43.  
  44. #ifdef URT
  45. unsigned char **outptr;        /* Output buffer */
  46. static int count_rle_rows();
  47. #endif
  48.  
  49. /*
  50.  * Convert floating-point (0.-1.) to unsigned char (0-255), with no gamma
  51.  * correction.
  52.  */
  53. unsigned char
  54. correct(x)
  55. Float x;
  56. {
  57.     /*
  58.      * Truncate values < 0 or > 1.
  59.      */
  60.     if (x < 0)
  61.         return 0;
  62.     if (x > 1.)
  63.         return 255;
  64.     return (unsigned char)(x * 255.);
  65. }
  66.  
  67. #ifdef URT
  68. /*
  69.  * Open image file and write RLE header.
  70.  */
  71. void
  72. PictureStart(argv)
  73. char **argv;
  74. {
  75.     char gammacom[40];
  76.  
  77.     if (Options.framenum != Options.startframe) {
  78.         /*
  79.          * We've been here before;
  80.          * write a new header and return.
  81.          */
  82.         rle_put_setup(&rle_dflt_hdr);
  83.         return;
  84.     }
  85.     /*
  86.      * If Appending, then we know that outfile is valid, 'cause
  87.      * we've already read its header.
  88.      */
  89.     if (Options.appending) {
  90.         Options.pictfile = fopen(Options.imgname, "a");
  91.         if (Options.pictfile == (FILE *)0)
  92.             RLerror(RL_PANIC, "Cannot append to %s?!\n",
  93.                     Options.imgname);
  94.         rle_dflt_hdr.rle_file = Options.pictfile;
  95.         rle_put_init(&rle_dflt_hdr);
  96.         /*
  97.          * Append "linefeed" to last line in outfile.
  98.          */
  99.         if (Screen.miny > rle_dflt_hdr.ymin)
  100.             rle_skiprow(&rle_dflt_hdr, 1);
  101.     } else {
  102.         /*
  103.          * Starting image from scatch.
  104.          */
  105.         if (Options.imgname) {
  106.             Options.pictfile = fopen(Options.imgname, "w");
  107.             if (Options.pictfile == (FILE *)NULL)
  108.                 RLerror(RL_ABORT,"Cannot open %s for writing.",
  109.                     Options.imgname);
  110.         } else
  111.             Options.pictfile = stdout;
  112.  
  113.         rle_dflt_hdr.xmax = Screen.maxx;
  114.         rle_dflt_hdr.ymax = Screen.maxy;
  115.         rle_dflt_hdr.xmin = Screen.minx;
  116.         rle_dflt_hdr.ymin = Screen.miny;
  117.         rle_dflt_hdr.alpha = Options.alpha;
  118.         if (Options.alpha)
  119.             RLE_SET_BIT(rle_dflt_hdr, RLE_ALPHA);
  120.         if (Options.exp_output) {
  121.             RLE_SET_BIT(rle_dflt_hdr, RLE_BLUE + 1);
  122.             rle_dflt_hdr.ncolors = 4;
  123.             rle_putcom("exponential_data", &rle_dflt_hdr);
  124.         }
  125.         else
  126.             rle_dflt_hdr.ncolors = 3;
  127.         /*
  128.           * Document image gamma in RLE comment area.
  129.          * Options.gamma has been inverted.
  130.           */
  131.         (void)sprintf(gammacom, "display_gamma=%g", 1./Options.gamma);
  132.         rle_putcom(gammacom, &rle_dflt_hdr);
  133.         /*
  134.           * Document command line in RLE history.
  135.           */
  136.         rle_addhist(argv, (rle_hdr *)0, &rle_dflt_hdr);
  137.         rle_dflt_hdr.rle_file = Options.pictfile;
  138.         rle_put_setup(&rle_dflt_hdr);
  139.         /*
  140.           * Flush the header.  If we don't, and LINDA forks off
  141.           * a bunch of workers, strange things will happen (they'll
  142.           * all flush the buffer when they die, and you end up with
  143.           * lots of headers at the end of the file).
  144.           */
  145.         (void)fflush(rle_dflt_hdr.rle_file);
  146.     }
  147.  
  148.     if (Options.zbufprint) {
  149.         zbuffer.outfile = Options.imgname ?
  150.         strsave (Options.imgname) : NULL;
  151.         zbuffer.argv = argv;
  152.     }
  153.  
  154.     if (rle_row_alloc(&rle_dflt_hdr, &outptr) < 0)
  155.         RLerror(RL_PANIC, "Unable to allocate image memory.\n");
  156. }
  157.  
  158. /*
  159.  * Read RLE header to which we are appending in order determine
  160.  * old resolution, window location, and the like.
  161.  */
  162. void
  163. PictureSetWindow()
  164. {
  165.     if (Options.imgname == (char *)NULL)
  166.         RLerror(RL_ABORT,
  167.             "No partially-completed image file specified.\n");
  168.  
  169.     /*
  170.      * Open image and read RLE header.
  171.      */
  172.     Options.pictfile = fopen(Options.imgname, "r");
  173.     if (Options.pictfile == (FILE *)NULL) {
  174.         fprintf(stderr,
  175.             "Cannot open image file \"%s\".  Creating new file.\n",
  176.             Options.imgname);
  177.         Options.appending = FALSE;
  178.         return;
  179.     }
  180.     rle_dflt_hdr.rle_file = Options.pictfile;
  181.     rle_get_setup_ok(&rle_dflt_hdr, "rayshade", Options.imgname);
  182.  
  183.     /*
  184.      * If user specified a window that does not match what's in
  185.      * the header, complain.
  186.     if (Screen.minx != UNSET && Screen.minx != rle_dflt_hdr.xmin ||
  187.         Screen.miny != UNSET && Screen.miny != rle_dflt_hdr.ymin ||
  188.         Screen.maxx != UNSET && Screen.maxx != rle_dflt_hdr.xmax ||
  189.         Screen.maxy != UNSET && Screen.maxy != rle_dflt_hdr.ymax)
  190.         RLerror(RL_ADVISE, "Image window: %d - %d, %d - %d.\n",
  191.             rle_dflt_hdr.xmin, rle_dflt_hdr.xmax,
  192.             rle_dflt_hdr.ymin, rle_dflt_hdr.ymax);
  193.      */
  194.     /*
  195.      * Set window.
  196.      */
  197.     Screen.minx = rle_dflt_hdr.xmin;
  198.     Screen.miny = rle_dflt_hdr.ymin;
  199.     Screen.maxx = rle_dflt_hdr.xmax;
  200.     Screen.maxy = rle_dflt_hdr.ymax;
  201.  
  202.     /*
  203.      * Set alpha.  Warn the user if the alpha option doesn't reflect
  204.      * what's already been rendered.
  205.      */
  206.     if (Options.alpha != rle_dflt_hdr.alpha)
  207.         RLerror(RL_WARN, "Image %s %s an alpha channel.\n",
  208.             Options.imgname,
  209.             rle_dflt_hdr.alpha ? "has" : "does not have");
  210.  
  211.     Options.alpha = rle_dflt_hdr.alpha;
  212.  
  213.     /*
  214.      * Determine number of scanlines written to file.
  215.      */
  216.     Screen.miny += count_rle_rows(&rle_dflt_hdr);
  217.     if (Screen.miny > Screen.maxy) {
  218.         fprintf(stderr, "\"%s\" is a complete image.\n",
  219.             Options.imgname);
  220.         exit(0);
  221.     }
  222.     fprintf(Stats.fstats,"Continuing \"%s\" at scanline #%d.\n",
  223.         Options.imgname, Screen.miny);
  224.     (void)fclose(Options.pictfile);
  225. }
  226.  
  227. static int
  228. count_rle_rows(hdr)
  229. rle_hdr *hdr;
  230. {
  231.     int y, ynext;
  232.  
  233.     for (y = hdr->ymin - 1; (ynext = rle_getskip(hdr)) != 32768; y = ynext)
  234.         ;
  235.  
  236.     /*
  237.      * If we have not reached physical EOF, then we must be at logical EOF
  238.      * which means the image is complete regardless of the amount of
  239.      * scanline data present.
  240.      */
  241.     if (!feof(hdr->rle_file))
  242.         y = hdr->ymax;
  243.  
  244.     return y - hdr->ymin + 1;
  245. }
  246.  
  247. /*
  248.  * Write a scanline of output.
  249.  * "buf" is an array of Color structures of size Screen.xsize.  Each color
  250.  * component is normalized to [0, 1.].
  251.  */
  252. void
  253. PictureWriteLine(buf)
  254. Pixel *buf;
  255. {
  256.     register int i, chan;
  257.     float floats[3];
  258.     rle_pixel pixels[4];
  259.  
  260.     for(i = 0; i < Screen.xsize; i++) {
  261.         if (!Options.exp_output) {
  262.             /*
  263.              * Scale colors to fit unsigned char and check for
  264.              * over/underflow.
  265.              */
  266.             outptr[0][i] = CORRECT(buf[i].r);
  267.             outptr[1][i] = CORRECT(buf[i].g);
  268.             outptr[2][i] = CORRECT(buf[i].b);
  269.         } else {
  270.             /*
  271.              * Convert 3 floats to 4 unsigned chars for
  272.              * 'exponential_data' RLE file.
  273.              */
  274.             floats[0] = GAMMACORRECT(buf[i].r);
  275.             floats[1] = GAMMACORRECT(buf[i].g);
  276.             floats[2] = GAMMACORRECT(buf[i].b);
  277.             float_to_exp( 3, floats, pixels );
  278.             for (chan = 0; chan <= 3; chan++)
  279.                 outptr[chan][i] = pixels[chan];
  280.         }
  281.         if (Options.alpha)
  282.             /*
  283.              * Don't gamma correct alpha channel.
  284.              */
  285.             outptr[-1][i] = correct(buf[i].alpha);
  286.     }
  287.     rle_putrow(outptr, Screen.xsize, &rle_dflt_hdr);
  288. }
  289.  
  290. /*
  291.  * End the frame.
  292.  */
  293. void
  294. PictureFrameEnd()
  295. {
  296.     rle_puteof(&rle_dflt_hdr);
  297. }
  298.  
  299. /*
  300.  * Close image file.
  301.  */
  302. void
  303. PictureEnd()
  304. {
  305.     (void)fclose(Options.pictfile);
  306. }
  307.  
  308. #else /* !URT */
  309. void
  310. PictureStart(argv)
  311. char **argv;
  312. {
  313.     if (Options.imgname) {
  314.         Options.pictfile = fopen(Options.imgname, "w");
  315.         if (Options.pictfile == (FILE *)NULL)
  316.             RLerror(RL_ABORT, "Cannot open %s for writing.",
  317.                 Options.imgname);
  318.     } else
  319.         Options.pictfile = stdout;
  320.  
  321.     fprintf(Options.pictfile,"%d %d\n",Screen.xsize, Screen.ysize);
  322.  
  323.     (void)fflush(Options.pictfile);
  324. }
  325.  
  326. void
  327. PictureWriteLine(buf)
  328. Pixel *buf;
  329. {
  330.     register int i;
  331.  
  332.     for (i = 0; i < Screen.xsize; i++) {
  333.         (void)fputc((int)CORRECT(buf[i].r), Options.pictfile);
  334.         (void)fputc((int)CORRECT(buf[i].g), Options.pictfile);
  335.         (void)fputc((int)CORRECT(buf[i].b), Options.pictfile);
  336.     }
  337.     (void)fflush(Options.pictfile);
  338. }
  339.  
  340. void
  341. PictureFrameEnd()
  342. {
  343.     /*
  344.      * Don't do anything -- generic format has no end-of-image marker.
  345.      */
  346. }
  347.  
  348. void
  349. PictureEnd()
  350. {
  351.     (void)fclose(Options.pictfile);
  352. }
  353.  
  354. #endif /* URT */
  355.